﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;
using System.Text;

namespace SharpSoft.Data
{
    public static class DataTableHelper
    {
        /// <summary>
        /// 数据表转为实体类数组
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="table"></param>
        /// <returns></returns>
        public static T[] ToEntities<T>(this DataTable dt) where T : class, new()
        {
            if (dt == null)
                return null;
            if (dt.Rows.Count == 0)
            {
                return new T[0];
            }
            List<T> result = new List<T>();
            foreach (DataRow dr in dt.Rows)
            {
                T obj = dr.ToEntity<T>();
                result.Add(obj);
            }
            return result.ToArray();
        }

        public static T ToEntity<T>(this DataRow row) where T : class, new()
        {
            if (row == null)
                return null;

            T obj = new T();
            var t = typeof(T);
            for (int i = 0; i < row.Table.Columns.Count; i++)
            {
                PropertyInfo propertyInfo = t.GetProperty(row.Table.Columns[i].ColumnName, BindingFlags.Public | BindingFlags.Instance);

                object value = null;
                if (row.RowState == DataRowState.Deleted)
                {//已删除的行获取其原始数据
                    value = row[i, DataRowVersion.Original];
                }
                else
                {
                    value = row[i, DataRowVersion.Current];
                }
                if (propertyInfo != null)
                {
                    value = SqlUtility.ConvertToTargetType(value, propertyInfo.PropertyType);
                    propertyInfo.SetValue(obj, value, null);
                }
            }
            return obj;

        }

        /// <summary>
        /// 用实体数据填充数据表
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="table"></param>
        /// <param name="data"></param>
        public static void FillByEntities<T>(this DataTable table, T[] data)
        {
            var t = typeof(T);
            foreach (var item in data)
            {
                DataRow row = table.NewRow();
                row.BeginEdit();
                foreach (DataColumn column in table.Columns)
                {
                    var p = t.GetProperty(column.ColumnName);
                    if (p != null)
                    {
                        row[column] = p.GetValue(item) ?? DBNull.Value;
                    }
                }
                row.EndEdit();
                table.Rows.Add(row);
            }
        }
        /// <summary>
        /// 将实体数组转为<see cref="System.Data.DataTable"/>
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="entities"></param>
        /// <returns></returns>
        public static DataTable EntitiesToDataTable<T>(T[] entities)
        {
            var dt = CreateFromType(typeof(T));
            dt.FillByEntities(entities);
            dt.AcceptChanges();
            return dt;
        }

        /// <summary>
        /// 从运行时类型创建数据表结构
        /// </summary>
        /// <param name="t"></param>
        /// <returns></returns>
        public static DataTable CreateFromType(Type t)
        {
            DataTable dt = new DataTable(t.Name);
            var ps = t.GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (var p in ps)
            {
                DataColumn column;
                var type = p.PropertyType;
                if ((type.IsConstructedGenericType && typeof(Nullable<>).Equals(type.GetGenericTypeDefinition())))
                {//如果是Nullable泛型
                    type = p.PropertyType.GetGenericArguments()[0];
                    column = new DataColumn(p.Name, type) { AllowDBNull = true };

                }
                else
                {
                    column = new DataColumn(p.Name, type);
                }
                dt.Columns.Add(column);
            }
            return dt;
        }
    }
}
